/*
 * Test app for frequency conversion to Network.Wifi.Channel uma metric.
 *
 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include <stdio.h>

enum connman_channel {
	CONNMAN_CHANNEL_UNDEF = 0,
	CONNMAN_CHANNEL_2412 = 1,
	CONNMAN_CHANNEL_2417 = 2,
	CONNMAN_CHANNEL_2422 = 3,
	CONNMAN_CHANNEL_2427 = 4,
	CONNMAN_CHANNEL_2432 = 5,
	CONNMAN_CHANNEL_2437 = 6,
	CONNMAN_CHANNEL_2442 = 7,
	CONNMAN_CHANNEL_2447 = 8,
	CONNMAN_CHANNEL_2452 = 9,
	CONNMAN_CHANNEL_2457 = 10,
	CONNMAN_CHANNEL_2462 = 11,
	CONNMAN_CHANNEL_2467 = 12,
	CONNMAN_CHANNEL_2472 = 13,
	CONNMAN_CHANNEL_2484 = 14,

	CONNMAN_CHANNEL_5180 = 15,
	CONNMAN_CHANNEL_5200 = 16,
	CONNMAN_CHANNEL_5220 = 17,
	CONNMAN_CHANNEL_5240 = 18,
	CONNMAN_CHANNEL_5260 = 19,
	CONNMAN_CHANNEL_5280 = 20,
	CONNMAN_CHANNEL_5300 = 21,
	CONNMAN_CHANNEL_5320 = 22,

	CONNMAN_CHANNEL_5500 = 23,
	CONNMAN_CHANNEL_5520 = 24,
	CONNMAN_CHANNEL_5540 = 25,
	CONNMAN_CHANNEL_5560 = 26,
	CONNMAN_CHANNEL_5580 = 27,
	CONNMAN_CHANNEL_5600 = 28,
	CONNMAN_CHANNEL_5620 = 29,
	CONNMAN_CHANNEL_5640 = 30,
	CONNMAN_CHANNEL_5660 = 31,
	CONNMAN_CHANNEL_5680 = 32,
	CONNMAN_CHANNEL_5700 = 33,

	CONNMAN_CHANNEL_5745 = 34,
	CONNMAN_CHANNEL_5765 = 35,
	CONNMAN_CHANNEL_5785 = 36,
	CONNMAN_CHANNEL_5805 = 37,
	CONNMAN_CHANNEL_5825 = 38,

	CONNMAN_CHANNEL_5170 = 39,
	CONNMAN_CHANNEL_5190 = 40,
	CONNMAN_CHANNEL_5210 = 41,
	CONNMAN_CHANNEL_5230 = 42,

	/* NB: ignore old 11b bands 2312..2372 and 2512..2532 */
	/* NB: ignore regulated bands 4920..4980 and 5020..5160 */

#ifdef CONFIG_PSB_SUPPORT
	CONNMAN_CHANNEL_PSB_4940 = 43,	/* NB: PSB center freq's are +.5MHz */
	CONNMAN_CHANNEL_PSB_4941 = 44,
	CONNMAN_CHANNEL_PSB_4942 = 45,
	CONNMAN_CHANNEL_PSB_4943 = 46,
	CONNMAN_CHANNEL_PSB_4944 = 47,
	CONNMAN_CHANNEL_PSB_4947 = 48,
	CONNMAN_CHANNEL_PSB_4952 = 49,
	CONNMAN_CHANNEL_PSB_4957 = 50,
	CONNMAN_CHANNEL_PSB_4962 = 51,
	CONNMAN_CHANNEL_PSB_4967 = 52,
	CONNMAN_CHANNEL_PSB_4972 = 53,
	CONNMAN_CHANNEL_PSB_4977 = 54,
	CONNMAN_CHANNEL_PSB_4982 = 55,
	CONNMAN_CHANNEL_PSB_4985 = 56,
	CONNMAN_CHANNEL_PSB_4986 = 57,
	CONNMAN_CHANNEL_PSB_4987 = 58,
	CONNMAN_CHANNEL_PSB_4988 = 59,
	CONNMAN_CHANNEL_PSB_4989 = 60,
#endif
	CONNMAN_CHANNEL_MAX
};

static void connman_info(const char *fmt, ...)
{
	(void) fmt;
}

/*
 * Map WiFi frequency to UMA enum value.
 */
static enum connman_channel __map_frequency(int frequency)
{
	if (2412 <= frequency && frequency <= 2472) {
		if (((frequency - 2412) % 5) == 0)
			return CONNMAN_CHANNEL_2412 + (frequency - 2412) / 5;
	} else if (frequency == 2484) {
		return CONNMAN_CHANNEL_2484;
	} else if (5170 <= frequency && frequency <= 5230) {
		if ((frequency % 20) == 0)
			return CONNMAN_CHANNEL_5180 + (frequency - 5180) / 20;
		if ((frequency % 20) == 10)
			return CONNMAN_CHANNEL_5170 + (frequency - 5170) / 20;
		/* NB: fall through to return undefined */
	} else if (5240 <= frequency && frequency <= 5320) {
		if (((frequency - 5180) % 20) == 0)
			return CONNMAN_CHANNEL_5180 + (frequency - 5180) / 20;
	} else if (5500 <= frequency && frequency <= 5700) {
		if (((frequency - 5500) % 20) == 0)
			return CONNMAN_CHANNEL_5500 + (frequency - 5500) / 20;
	} else if (5745 <= frequency && frequency <= 5825) {
		if (((frequency - 5745) % 20) == 0)
			return CONNMAN_CHANNEL_5745 + (frequency - 5745) / 20;
#ifdef CONFIG_PSB_SUPPORT
	} else if (4940 <= frequency && frequency <= 4990) {
		/* Public Safety Band */
		return CONNMAN_CHANNEL_PSB_4940 + (frequency * 10) +
		    ((frequency % 5) == 2 ? 5 : 0) - 49400) / 5;
#endif
	}
	connman_info("%s: no mapping for WiFi frequency %d", __func__,
	    frequency);
	return CONNMAN_CHANNEL_UNDEF;
}

#define	NBBY 8
static unsigned char map[6000 / NBBY];

static void setbit(x) { map[x / NBBY] |= 1<<(x % NBBY); }
static int isbitset(x) { return map[x / NBBY] & (1<<(x % NBBY)); }

static void check(int freq, enum connman_channel expected,
    enum connman_channel mapped)
{
	if (isbitset(freq))
		printf("frequency %d already checked\n", freq);
	if (mapped != expected)
		printf("frequency %d mapped to %d but expected %d\n", freq,
		   mapped, expected);
	setbit(freq);
}

int
main(int argc, char *argv[])
{
	int i, freq;

	/* check known mappings */
	for (freq = 2412, i = 0; freq <= 2472; freq += 5, i++)
		check(freq, CONNMAN_CHANNEL_2412+i, __map_frequency(freq));
	check(2484, CONNMAN_CHANNEL_2484, __map_frequency(2484));
	for (freq = 5180, i = 0; freq <= 5320; freq += 20, i++)
		check(freq, CONNMAN_CHANNEL_5180+i, __map_frequency(freq));
	for (freq = 5170, i = 0; freq <= 5230; freq += 20, i++)
		check(freq, CONNMAN_CHANNEL_5170+i, __map_frequency(freq));
	for (freq = 5500, i = 0; freq <= 5700; freq += 20, i++)
		check(freq, CONNMAN_CHANNEL_5500+i, __map_frequency(freq));
	for (freq = 5745, i = 0; freq <= 5825; freq += 20, i++)
		check(freq, CONNMAN_CHANNEL_5745+i, __map_frequency(freq));
	/* TODO(sleffler) PSB support */

	/* sweep unchecked frequencies to verify they map to undefined */
	for (freq = 2300; freq <= 6000; freq++)
		if (!isbitset(freq))
			check(freq, CONNMAN_CHANNEL_UNDEF,
			    __map_frequency(freq));
}
